#!/bin/sh
#
# config -- Configure the common variables
#
# Copyright (C) 2016-2021 Wu Zhangjin <falcon@ruma.tech>
#

if [ -z "$TOP_DIR" ]; then
  TOP_DIR="$(cd "$(dirname "$0")"/../../ && pwd)"
else
  TOP_DIR="$(cd "$(dirname "$TOP_DIR"/null)" && pwd)"
fi

# Basic files/directories
GIT_DIR="$TOP_DIR"/.git
GIT_WORKDIR=//.git

LAB_DIR="$TOP_DIR"/labs
LAB_WORKDIR=//labs

TOOL_DIR="$TOP_DIR"/tools
TOOL_WORKDIR=//tools

CONFIGS_DIR="$TOP_DIR"/configs/
CONFIG_WORKDIR=//configs

BASE_DIR="$TOP_DIR"/base
TPROXY_DIR="$BASE_DIR"/tproxy
WPROXY_DIR="$BASE_DIR"/wproxy

LAB_CURRENT="$LAB_DIR"/.current_lab

get_current()
{
  # Allow to pass lab name
  if [ ! -n "$current" ]; then
    [ -z "$CURRENT" ] && CURRENT=$1
  else
    CURRENT=$current
  fi

  if [ -z "$CURRENT" ]; then
    [ -f "$LAB_CURRENT" ] && CURRENT=$(cat "$LAB_CURRENT")
  else
    ls "$CONFIGS_DIR" | tr -d '/' | grep -E -v '^common$' | tr -s ' ' | tr ' ' '\n' | grep -q ^$CURRENT$
    [ $? -ne 0 -a -f "$LAB_CURRENT" ] && CURRENT=$(cat "$LAB_CURRENT")

    [ -z "$current" ] && echo $CURRENT | tr -d '\r\n' > "$LAB_CURRENT" &
  fi
}

get_current $1
CONFIG_DIR="$TOP_DIR"/configs/$CURRENT

CORE_SYSTEM_DIR="$TOOL_DIR"/system

CONFIG_TOOL_DIR="$CONFIG_DIR"/tools
CONFIG_DOCKER_DIR="$CONFIG_DIR"/docker
CONFIG_CONTAINER_DIR="$CONFIG_DIR"/docker/container
CONFIG_SYSTEM_DIR="$CONFIG_DIR"/system

# Share among labs
LAB_HOST="$TOP_DIR"/.host_name
LAB_OUTPUT="$TOP_DIR"/output

# Lab Specific
LAB_DOCKER="$CONFIG_DIR"/.docker_name
LAB_LOGIN="$CONFIG_DIR"/.login_method
LAB_VNC="$CONFIG_DIR"/.login_vnc

DOCKER_DIR="$TOOL_DIR"/docker
DOCKER_IDENTIFY_CMD="$DOCKER_DIR"/identify
DOCKER_VNC_CMD="$DOCKER_DIR"/vnc
DOCKER_WEBVNC_CMD="$DOCKER_DIR"/webvnc
DOCKER_IP_CMD="$DOCKER_DIR"/newip
DOCKER_LIST_CMD="$DOCKER_DIR"/list
DOCKER_RELEASE_CMD="$DOCKER_DIR"/release
DOCKER_BASH_CMD="$DOCKER_DIR"/bash
DOCKER_SSH_CMD="$DOCKER_DIR"/ssh
DOCKER_WEBSSH_CMD="$DOCKER_DIR"/webssh
DOCKER_LOGIN_CMD="$DOCKER_DIR"/login
DOCKER_EXPORT_CMD="$DOCKER_DIR"/export
DOCKER_RESIZE_CMD="$DOCKER_DIR"/resize
DOCKER_PUBLISH_CMD="$DOCKER_DIR"/publish
DOCKER_PULL_CMD="$DOCKER_DIR"/pull
DOCKER_GIT_PULL_CMD="$DOCKER_DIR"/git-pull
DOCKER_TPROXY_CMD="$DOCKER_DIR"/tproxy
DOCKER_CLEAN_CMD="$DOCKER_DIR"/clean
DOCKER_BUILD_CMD="$DOCKER_DIR"/build
DOCKER_RM_CMD="$DOCKER_DIR"/rm
DOCKER_RM_ALL_CMD="$DOCKER_DIR"/rm-all
DOCKER_RMI_ALL_CMD="$DOCKER_DIR"/rmi-all
DOCKER_RUN_CMD="$DOCKER_DIR"/run
DOCKER_CHOOSE_CMD="$DOCKER_DIR"/choose
DOCKER_STOP_CMD="$DOCKER_DIR"/stop
DOCKER_START_CMD="$DOCKER_DIR"/start
DOCKER_START_ALL_CMD="$DOCKER_DIR"/start-all
DOCKER_UNLOCK_CMD="$DOCKER_DIR"/unlock
DOCKER_XTERM_CMD="$DOCKER_DIR"/get_xterm
DOCKER_CMD_CMD="$DOCKER_DIR"/cmd
DOCKER_NOTIFY_CMD="$DOCKER_DIR"/notify
DOCKER_LIBS="$DOCKER_DIR"/libs
DOCKER_FILE="$CONFIG_DIR"/Dockerfile

LAB_FULLNAME="$CONFIG_DIR"/fullname
LAB_IMAGE="$CONFIG_DOCKER_DIR"/name
LAB_ENVS="$CONFIG_DOCKER_DIR"/envs
LAB_CAPS="$CONFIG_DOCKER_DIR"/caps
LAB_DNS="$CONFIG_DOCKER_DIR"/dns
LAB_DEVICES="$CONFIG_DOCKER_DIR"/devices
LAB_LIMITS="$CONFIG_DOCKER_DIR"/limits
LAB_PORTMAP="$CONFIG_DOCKER_DIR"/portmap
LAB_VOLUMEMAP="$CONFIG_DOCKER_DIR"/volumemap
LAB_BRANCH="$CONFIG_DOCKER_DIR"/branch
LAB_PLATFORM="$CONFIG_DOCKER_DIR"/platform
LAB_SUBNET="$CONFIG_DOCKER_DIR"/subnet

LAB_TPROXY_LIMITS="$TPROXY_DIR"/limits
LAB_WPROXY_LIMITS="$WPROXY_DIR"/limits

LAB_LOGO="$CONFIG_DIR"/lab-logo.png
LAB_HOST_RUN="$CONFIG_TOOL_DIR"/host-run

# Container writable
LAB_UNIX_PWD="$CONFIG_CONTAINER_DIR"/.unix_pwd
LAB_VNC_PWD="$CONFIG_CONTAINER_DIR"/.vnc_pwd
LAB_VNC_PWD_VIEWONLY="$CONFIG_CONTAINER_DIR"/.vnc_pwd_viewonly
LAB_VNC_IP="$CONFIG_CONTAINER_DIR"/.vnc_ip
LAB_VNC_TOKEN="$CONFIG_CONTAINER_DIR"/.vnc_token
LAB_UNIX_USER="$CONFIG_CONTAINER_DIR"/.unix_user
LAB_UNIX_UID="$CONFIG_CONTAINER_DIR"/.unix_uid
LAB_HOST_NAME="$CONFIG_CONTAINER_DIR"/.host_name
LAB_MIRROR_SITE="$CONFIG_CONTAINER_DIR"/.mirror_site

# Host side only
LAB_CONTAINER_NAME="$CONFIG_DOCKER_DIR"/.container_name
LAB_CONTAINER_ID="$CONFIG_DOCKER_DIR"/.container_id
LAB_TPROXY="$CONFIG_DOCKER_DIR"/.tproxy
LAB_TPROXY_IP="$CONFIG_DOCKER_DIR"/.tproxy_ip
LAB_SCREEN_SIZE="$CONFIG_DOCKER_DIR"/.screen_size
LAB_VNC_SHARED="$CONFIG_DOCKER_DIR"/.vnc_shared
LAB_VNC_IDENTIFY="$CONFIG_DOCKER_DIR"/.vnc_identify
LAB_UNIX_IDENTIFY="$CONFIG_DOCKER_DIR"/.unix_identify
LAB_SUDO_IDENTIFY="$CONFIG_DOCKER_DIR"/.sudo_identify
LAB_WEB_BROWSER="$CONFIG_DOCKER_DIR"/.web_browser
LAB_PRIV_MODE="$CONFIG_DOCKER_DIR"/.priv_mode
LAB_XTERM="$CONFIG_DOCKER_DIR"/.xterm
LAB_DESKTOP="$CONFIG_DOCKER_DIR"/.desktop

# Default variables
[ -z "$LAB_SECURITY" ] && LAB_SECURITY=0
DEF_UNIX_USER=ubuntu
DEF_UNIX_UID=1000
DEF_HOSTNAME=localhost
DEF_DESKTOP=auto
DEF_PWD_LENGTH=6
DEF_PWD_TOTAL=100

DEF_TOKEN_LENGTH=6
[ -z "$TOKEN_LENGTH" ] && TOKEN_LENGTH=$DEF_TOKEN_LENGTH
[ -z "$DEF_TOKEN_DIR" ] && DEF_TOKEN_DIR=.vnc-tokens
DEF_VNC_IP="0.0.0.0"
DEF_VNC_TOKEN=""

# FIXME: This may conflict with another network with the same subnet
# If so, please customize one in configs/linux-lab/docker/subnet
DEF_SUBNET="172.20.0.0/16"

DEF_MIRROR_SITE="mirrors.ustc.edu.cn"

for cs in sha1sum shasum; do
  which $cs >/dev/null 2>&1 && DEF_ENCRYPT_CMD=$cs && break
done
[ -z "$ENCRYPT_CMD" ] && ENCRYPT_CMD=$DEF_ENCRYPT_CMD

# Variables passed from host to container
VARS="UNIX_USER UNIX_UID UNIX_PWD VNC_PWD VNC_PWD_VIEWONLY VNC_IP VNC_TOKEN TPROXY_IP TPROXY VNC_SHARED SCREEN_SIZE HOST_NAME UNIX_IDENTIFY VNC_IDENTIFY SUDO_IDENTIFY HOST_OS LAB_SECURITY MIRROR_SITE PWD_LENGTH PWD_TOTAL DESKTOP"

debug_print ()
{
  [ "x$DEBUG" = "x1" ] && echo "DEBUG: $1"
  return 0
}

debug_end ()
{
  debug_print "Done"
}


log_print ()
{
  [ "x$LOGGING" = "x1" ] && echo "LOG: $1"
  return 0
}

log_end ()
{
  log_print "Done"
}

info_print ()
{
  echo "INFO: $1"
}

warn_print ()
{
  echo "WARN: $1"
}

err_print ()
{
  echo "ERR: $1"
}

# Security related
# 0: with root permission by default, sharable, for private usage
# 1: highest security level, ssl, encrypted, https, no root, no sudo, not sharable, for security product
# 2: second security level, nossl, not encrypted, http, no root, no sudo, not sharable, for normal product
# 3: third security leve, nossl, not encrypted, http, root available with sudo and password, sharable

# Lock the important files for security
__do_lock ()
{
  log_print "__do_lock"

  [ `id -u` -ne 0 ] && SUDO=sudo

  [ -d "$CONFIG_DOCKER_DIR" ] && \
    $SUDO find "$CONFIG_DOCKER_DIR" -iname ".[^.]*" -exec chmod -f -R a-rw "{}" \;

  which chattr >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    $SUDO chattr -R +i "$CONFIGS_DIR"
    $SUDO chattr -R +i "$TOOL_DIR"
  fi
}

# Unlock the important files for configuration
__do_unlock ()
{
  log_print "__do_unlock"

  [ `id -u` -ne 0 ] && SUDO=sudo

  which chattr >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    $SUDO chattr -R -i "$CONFIGS_DIR"
    $SUDO chattr -R -i "$TOOL_DIR"
  fi
  [ -d "$CONFIG_DOCKER_DIR" ] && \
    $SUDO find "$CONFIG_DOCKER_DIR" -iname ".[^.]*" -exec chmod -f -R 664 "{}" \;
}

do_lock ()
{
  [ $LAB_SECURITY -ge 1 ] && __do_lock
}

do_unlock ()
{
  [ $LAB_SECURITY -ge 1 ] && __do_unlock
}


if [ $LAB_SECURITY -eq 1 ]; then
  WEB_NOSSL=0
  WEB_ENCRYPT=1
  WEB_HTTP=https
  # Account password locked, forbid the identify
  DEF_UNIX_IDENTIFY=0
  # No sudo, no way to switch to root in clients
  DEF_SUDO_IDENTIFY=0
  # Enable vnc identify
  DEF_VNC_IDENTIFY=1
  [ -z "$VNC_SHARED" ] && VNC_SHARED=0
elif [ $LAB_SECURITY -eq 2 ]; then
  WEB_NOSSL=1
  WEB_ENCRYPT=0
  WEB_HTTP=http
  # Not locked
  DEF_UNIX_IDENTIFY=1
  # No sudo, no way to switch to root in clients
  DEF_SUDO_IDENTIFY=0
  # Enable vnc identify
  DEF_VNC_IDENTIFY=1
  [ -z "$VNC_SHARED" ] && VNC_SHARED=0
elif [ $LAB_SECURITY -eq 3 ]; then
  WEB_NOSSL=1
  WEB_ENCRYPT=0
  WEB_HTTP=http
  # Not locked
  DEF_UNIX_IDENTIFY=1
  # Can get root simply with sudo and password
  DEF_SUDO_IDENTIFY=1
  # Enable vnc identify
  DEF_VNC_IDENTIFY=1
  [ -z "$VNC_SHARED" ] && VNC_SHARED=1
else
  WEB_NOSSL=1
  WEB_ENCRYPT=0
  WEB_HTTP=http
  # Not locked
  DEF_UNIX_IDENTIFY=1
  # Can get root simply with sudo and no password
  DEF_SUDO_IDENTIFY=2
  # Enable vnc identify
  DEF_VNC_IDENTIFY=1
  [ -z "$VNC_SHARED" ] && VNC_SHARED=1
fi

get_var () #VAR #defval
{
  local var_value
  local VAR
  local defval

  VAR=$1
  defval=$2

  # Get potential variable cache file
  var_file="`eval echo \\${LAB_$VAR}`"

  # Init it as user input
  var_value=`eval echo \\$${VAR}`

  # Load from variable cached file, if no user input specified
  if [ -f "$var_file" -a -z "$var_value" ]; then
    eval var_value=\\\'$\(sed -e \'':a;N;$!ba;s/\r//g;s/\n/ /g;s/#[^ ]* //g;s%^\s*$%%g;s%\s\{1,\}$%%g'\' \'$var_file\'\)\\\'
    eval `eval echo \\$VAR='$var_value'`
    var_value="`eval echo '$'${VAR}`"
  fi

  # If no variable specified or cached, use the default value if specified, otherwise, reserve empty
  if [ -z "$var_value" ]; then
    if [ -n "$defval" ]; then
      eval `eval echo \\$VAR='$defval'`
    else
      defval="`eval echo '$DEF_'${VAR}`"
      eval `eval echo \\$VAR='$defval'`
    fi
  fi
  debug_print "`eval echo GET: $VAR=\\$${VAR}`"
}

get_vars ()
{
  for var in $@; do
    debug_print "Read $var"
    get_var $var
    debug_end
  done
}

set_var () #VAR
{
  local VAR
  local var
  local var_file

  VAR=$1

  var=`eval echo \\$${VAR} | grep -E -v "^$|^ *$"`
  var_file="`eval echo \\${LAB_$VAR}`"

  debug_print "SET: Save '$var' to $var_file"

  [ -n "$var" ] && echo "$var" | sed -e ':a;N;$!ba;s/\r//g;s%^\s*$%%g;s%\s\{1,\}$%%g;s/ /\n/g' > "$var_file"
}

set_vars ()
{
  for var in $@; do
    debug_print "Save $var"
    set_var $var
    debug_end
  done
}

host_init()
{
  . "$DOCKER_LIBS"

  get_host_os

  # Shell scripts is very slow in Windows, enable more logging to increase the responsibility
  if [ -z "$LOGGING" ]; then
    if [ "x$HOST_OS" = "xWindows" ]; then
      LOGGING=1
    else
      LOGGING=0
    fi
  fi

  which docker >/dev/null 2>&1
  [ $? -ne 0 ] && prepare_docker

  if [ "x$HOST_OS" = "xWindows" ]; then
    prepare_docker_for_windows >&2
    # add .host_name.$DOCKER for both of toolbox and desktop
    [ -n "$DOCKER" ] && LAB_HOST="$TOP_DIR"/.host_name.$DOCKER
  fi

  [ -z "$TPROXY" ] && TPROXY=0
  [ -z "$VNC_NET_NAME" ] && VNC_NET_NAME=cloud-lab-net

  CONTAINER_SSH_PORT=22
  [ -z "$HOST_VNC_PORT" ] && HOST_VNC_PORT=6080
  [ -z "$HOST_SSH_PORT" ] && HOST_SSH_PORT=2222
  [ -z "$HOST_WEBSSH_PORT" ] && HOST_WEBSSH_PORT=4433

  TPROXY_NAME=proxy-client
  WPROXY_NAME=cloud-ubuntu-web
  TPROXY_TAG=latest
  WPROXY_TAG=20211228

  get_vars CONTAINER_NAME CONTAINER_ID IMAGE

  [ -z "$IMAGE" ] && IMAGE=tinylab/$CURRENT
  get_lab_user() { dirname $IMAGE; }
  LAB_NAME=$CURRENT
}

host_init
